﻿using System;
using System.Collections.Generic;
using HK.Core.Common;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Utils;
using HK.Editor.Common;
using HK.Editor.GUIEx.Protocol;
using HK.Editor.GUIEx.Protocol.Drag;
using HK.Editor.GUIEx.Protocol.Selection;
using HK.Editor.GUIEx.Styles;
using HK.Editor.Utils;
using UnityEditor;
using UnityEngine;

namespace HK.Editor.GUIEx.Drawer
{
    /// <summary>
    /// GUI绘制器 - 自定义
    /// </summary>
    public abstract class GUIDiyDrawer : ClassExtension, IGUIDiyDrawer
    {

        /// <summary>
        /// 保护构造函数
        /// </summary>
        /// <param name="iDrawFromUnity">是否从Unity调用绘制标志位</param>
        /// <param name="iOptions">选项</param>
        protected GUIDiyDrawer(bool iDrawFromUnity = false, int iOptions = (int)GUIOperateOptions.None)
        {
	        DrawFromUnity = iDrawFromUnity;
            _options = iOptions;
        }
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        /// <param name="iSelfProperty">自身Property</param>
        /// <param name="iDrawFromUnity">是否从Unity调用绘制标志位</param>
        /// <param name="iOptions">选项</param>
        protected GUIDiyDrawer(SerializedProperty iSelfProperty, bool iDrawFromUnity = false, int iOptions = (int)GUIOperateOptions.None) :
	        this(iDrawFromUnity, iOptions)
        {
            SelfProperty = iSelfProperty;
            ListSelection = Selection.ListSelection.Create(OnSelectionChanged);
            DragRectsList = Drag.DragRectsList.Create(0);
            ElementRects = Array.Empty<Rect>();
        }
        
        /// <summary>
        /// 初始化标志位
        /// </summary>
        protected bool Initialized { get; private set; } = false;

        /// <summary>
        /// 是否从Unity调用绘制标志位
        /// </summary>
        public bool DrawFromUnity { get; protected set; } = false;

#region Options

        /// <summary>
        /// 操作选项
        /// </summary>
        private int _options;

        /// <summary>
        /// 绘制背景
        /// </summary>
        public bool DrawBg => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.DrawBg);
        
        /// <summary>
        /// 只读
        /// </summary>
        public bool ReadOnly => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.ReadOnly);
        
        /// <summary>
        /// 可展开
        /// </summary>
        public bool Expandable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Expandable);
        
        /// <summary>
        /// 最小化
        /// </summary>
        public bool Minimize => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Minimize);
        
        /// <summary>
        /// 最大化
        /// </summary>
        public bool Maximize => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Maximize);
        
        /// <summary>
        /// 可追加
        /// </summary>
        public bool Addable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Addable);
		
        /// <summary>
        /// 可移除
        /// </summary>
        public bool Removable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Removable);
        
        /// <summary>
        /// 可枷锁
        /// </summary>
        public bool Lockable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Lockable);
        
        /// <summary>
        /// 可拖拽
        /// </summary>
        public bool Draggable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Draggable);
        
        /// <summary>
        /// 多行
        /// </summary>
        public bool MultiLine => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.MultiLine);
		
        /// <summary>
        /// 可检索
        /// </summary>
        public virtual bool Searchable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Searchable);
		
        /// <summary>
        /// 可排序
        /// </summary>
        public virtual bool Sortable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Sortable);
		
        /// <summary>
        /// 可点击
        /// </summary>
        public bool Clickable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.Clickable);
        
        /// <summary>
        /// 成员资产
        /// <para>* true : 成员为资产对象</para>
        /// </summary>
        public bool MemberAsset => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.MemberAsset);
        
        /// <summary>
        /// 成员无标题
        /// </summary>
        public bool MemberNoCaption => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.MemberNoCaption);
        
        /// <summary>
        /// 成员可拖拽
        /// </summary>
        public bool MemberDraggable => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.MemberDraggable);
        
        /// <summary>
        /// 成员唯一
        /// </summary>
        public bool MemberDistinct => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.MemberDistinct);
        
        /// <summary>
        /// 展开标志位
        /// </summary>
        public virtual bool IsExpanded
        {
            get => SelfProperty?.isExpanded ?? false;
            protected set
            {
                if(null == SelfProperty) return;
                SelfProperty.isExpanded = value;
            }
        }

        /// <summary>
        /// 按Property绘制
        /// </summary>
        public bool DrawProperty => UtilsBytes.CheckBytes(_options, (int)GUIOperateOptions.DrawProperty);
        
#endregion
        
#region Caption

        /// <summary>
        /// 标题
        /// </summary>
        public GUIContent Caption { get; private set; } = null;

        /// <summary>
        /// 创建标题
        /// </summary>
        /// <param name="iCaption">标题</param>
        /// <param name="iIcon">标题Icon</param>
        /// <param name="iTips">Tips</param>
        /// <returns>标题</returns>
        public GUIContent GenerateCaption(string iCaption, string iIcon = null, string iTips = null) =>
            UtilsGUIEx.CreateGuiContentWithIcon(iCaption, iIcon, iTips);

#endregion

#region Rect
        
        /// <summary>
        /// 余白 - 横向
        /// </summary>
        protected static readonly float HorizontalSpacing = EditorConst.HorizontalSpacing;

        /// <summary>
        /// 单行高度
        /// </summary>
        protected static readonly float  SingleLineHeight = EditorConst.DefaultLineHeight;

        /// <summary>
        /// Label先头缩进
        /// </summary>
        protected static readonly float LabelIntent = EditorConst.LabelIntent;

        /// <summary>
        /// 余白 : 纵向
        /// </summary>
        protected static readonly float VerticalSpacing = EditorConst.VerticalSpacing;
        
        /// <summary>
        /// 头部高度
        /// </summary>
        protected static readonly float  HeaderHeight = EditorConst.DefaultLineHeight + VerticalSpacing;

        /// <summary>
        /// Drag Mark宽度
        /// </summary>
        protected static readonly float DragMarkWidth = EditorConst.DragMarkWidth;

        /// <summary>
        /// 按钮宽度 - 仅是Icon的按钮
        /// </summary>
        protected static readonly float BtnWidthIconOnly = EditorConst.BtnWidthIconOnly;

        /// <summary>
        /// 宽度 - 按钮 - 较短
        /// </summary>
        protected static readonly float BtnWidthShort = EditorConst.BtnWidthShort;
        
        /// <summary>
        /// 总高度
        /// </summary>
        public float TotalHeight { get; protected set; } = 0.0f;
        
        /// <summary>
        /// 自身显示区域
        /// </summary>
        protected Rect SelfRect { get; private set; } = Rect.zero;

        /// <summary>
        /// 取得高度
        /// <para>* 包含子节点及其展开/不展开的实际高度</para>
        /// </summary>
        /// <returns>高度</returns>
        public virtual float CalcTotalHeight()
        {
            TotalHeight = HeaderHeight;
            return TotalHeight;
        }

        /// <summary>
        /// 取得Property的总高度
        /// <para>* 包括展开情况下的子Property的高度综合</para>
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <returns>Property的总高度</returns>
        protected virtual float GetPropertiesTotalHeight(SerializedProperty iProperty) => GetPropertiesTotalHeight(iProperty, Caption);       
        
        /// <summary>
        /// 取得Property的总高度
        /// <para>* 包括展开情况下的子Property的高度综合</para>
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <param name="iCaption">标题</param>
        /// <returns>Property的总高度</returns>
        protected virtual float GetPropertiesTotalHeight(SerializedProperty iProperty, GUIContent iCaption) => GetPropertyHeight(iProperty, iCaption);     
        
        /// <summary>
        /// 取得Property的高度
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">标题</param>
        /// <param name="iIncludeChild">是否包含子Property</param>
        /// <param name="iDeltaOffset">动态偏移量</param>
        /// <returns>Property的高度</returns>
        protected virtual float GetPropertyHeight(SerializedProperty iProperty, GUIContent iLabel, bool iIncludeChild = true, float iDeltaOffset = 0.0f)
        {
            return EditorGUI.GetPropertyHeight(iProperty, iLabel, iIncludeChild) + iDeltaOffset; 
        }
        
        private Rect[] _elementRects = null;
        /// <summary>
        /// 各个Element的矩形区域
        /// </summary>
        protected Rect[] ElementRects
        {
	        get => _elementRects; 
	        private set => _elementRects = value;
        }
        
        /// <summary>
        /// 重置成员Element矩形区域数据
        /// </summary>
        /// <param name="iSize">大小</param>
        protected virtual void ResizeElementRects(int iSize)
        {
	        Array.Resize(ref _elementRects, iSize);
        }

        /// <summary>
        /// 取得指定位置的Element的索引
        /// </summary>
        /// <param name="iMousePosition">鼠标点击位置</param>
        /// <returns>-1:无效; 其他:(非列表 - 0:代表自身被点击; 列表 - 成员Element的索引);</returns>
        protected virtual int MouseClickCheck(Vector2 iMousePosition) 
        {
	        if (SelfRect.Contains(iMousePosition)) 
	        {
		        return 0;
	        }

	        return -1;
        }
        
#endregion

        /// <summary>
        /// 背景色
        /// </summary>
        public virtual Color BgColor => Color.clear;
        
#region SerializedProperty

        /// <summary>
        /// 自身Property
        /// </summary>
        public SerializedProperty SelfProperty { get; private set; } = null;
        
        /// <summary>
        /// 查找序列化对象
        /// </summary>
        /// <param name="iSubProperty">子属性名</param>
        /// <returns>序列化对象</returns>
        protected SerializedProperty FindSerializedProperty(string iSubProperty)
        {
            if (null == SelfProperty) return null;
            var targetProperty = SelfProperty.FindPropertyRelative(iSubProperty);
            if (null == targetProperty)
            {
                Error ("FindSerializedProperty():The property of {0} is not exist!!!",
                    iSubProperty);
                return null;
            }
            return targetProperty;
        }

        /// <summary>
        /// 初始化序列化Property信息
        /// </summary>
        /// <param name="iSelf">自身Property</param>
        /// <returns>true:OK; false:NG;</returns>
        protected virtual bool InitSerializedProperties(SerializedProperty iSelf)
        {
            if (null == iSelf) return false;
            SelfProperty = iSelf;
            return null != SelfProperty;
        }

#endregion

#region Contents

        /// <summary>
        /// 初始化GUIContent
        /// </summary>
        protected virtual void InitContents() {}

#endregion

#region Styles

        /// <summary>
        /// 初始化风格
        /// </summary>
        protected virtual void InitStyles() {}

#endregion

#region Color

        /// <summary>
        /// 头部背景色
        /// </summary>
        protected virtual Color HeaderBgColor => Color.white;

#endregion

#region Drag

        /// <summary>
        /// 拖拽中
        /// </summary>
        public bool Dragging { get; protected set; } = false;

        /// <summary>
        /// 拖拽位置
        /// </summary>
        public float DragPosition { get; protected set; } = 0.0f;
        
        /// <summary>
        /// 拖拽方向
        /// <para>* 1 : 相对当前Element往后</para>
        /// <para>* -1 : 相对当前Element往前</para>
        /// </summary>
        public int DragDirection { get; protected set; } = 0;

        /// <summary>
        /// 拖拽元素列表
        /// </summary>
        protected IDragRectsList DragRectsList { get; private set; } = null;

        /// <summary>
        /// 拖拽代理
        /// </summary>
        public IDragAndDropSurrogate DragSurrogate { get; protected set; } = null;

        /// <summary>
        /// 创建一个拖拽代理
        /// </summary>
        /// <returns>拖拽代理</returns>
        protected virtual IDragAndDropSurrogate GenerateDragSurrogate() => null;
        
        /// <summary>
        /// 更新拖拽位置
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <param name="iBounds">拖拽范围</param>
        /// <param name="iDragRectsList">列表拖拽区域</param>
        /// <returns>true:有拖拽; false:无拖拽;</returns>
        private bool UpdateDragPosition(Vector2 iPosition, Rect iBounds, IDragRectsList iDragRectsList) 
        {
            var startIndex = 0;
            var endIndex = ListSelection.Length - 1;

            var minOffset = iDragRectsList[startIndex].DragOffset;
            var maxOffset = iDragRectsList[endIndex].Rect.height - iDragRectsList[endIndex].DragOffset;

            DragPosition = Mathf.Clamp(iPosition.y, iBounds.yMin + minOffset, iBounds.yMax - maxOffset);

            if (Mathf.Abs(DragPosition - PressPosition) > 1.0f) 
            {
                DragPosition = (int)Mathf.Sign(DragPosition - PressPosition);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 重现排序
        /// </summary>
        /// <param name="iDirection">方向(1:向后移动; -1:向前移动;)</param>
        /// <param name="iOffset">偏移</param>
        /// <param name="iSortList">列表排序回调</param>
        protected virtual void ReorderDraggedElements(int iDirection, int iOffset, System.Action iSortList) {}

#endregion

#region Selections

        /// <summary>
        /// 鼠标按下位置
        /// <para>* 仅仅记录纵方向的位置。即:y坐标</para>
        /// </summary>
        public float PressPosition { get; protected set; } = 0.0f;
        protected int PressIndex { get; set; } = 0;
        
        /// <summary>
        /// 拖拽之前列表选中信息
        /// </summary>
        protected IListSelection PrevListSelection { get; set; } = null;
        
        /// <summary>
        /// 列表选中情报
        /// </summary>
        protected IListSelection ListSelection { get; set; } = null;
        
        /// <summary>
        /// 校验是否能被选中
        /// <para>* 仅仅校验Element的索引在不在合法范围内</para>
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <returns>true:能被选中; false:反之;</returns>
        protected virtual bool CanSelect(int iIndex) => true;
        
        /// <summary>
        /// 判断指定位置是否在Element范围之内
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <param name="iIndex">Element索引</param>
        /// <returns>true:在Element范围内; false:反之;</returns>
        private bool IsPositionWithinElement(Vector2 iPosition, int iIndex) 
        {
	        return CanSelect(iIndex) && ElementRects[iIndex].Contains(iPosition);
        }
        
        /// <summary>
        /// 判断鼠标左键/中键按下？
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <returns>true:按下; false:未按下;</returns>
        private bool IsMouseLeftOrMidBtnDown(Event iEvent) 
        {
	        // 鼠标左键/中键按下
	        return iEvent.button == 0 || iEvent.button == 2;
        }
        
        /// <summary>
        /// 判断鼠标右键按下？
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <returns>true:按下; false:未按下;</returns>
        private bool IsMouseRightClickDown(Event iEvent) 
        {
	        // 鼠标左键/中键按下
	        return iEvent.button == 1;
        }
        
        /// <summary>
        /// 选中变更事件
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iSelected">选中/没选中</param>
        protected virtual void OnSelectionChanged(int iIndex, bool iSelected) {}
        
        /// <summary>
        /// 设置选中
        /// </summary>
        /// <param name="iIndex">选中Element索引</param>
        /// <param name="iSetKeyboardControl">设置Keyboard</param>
        /// <param name="iEvent">Event</param>
        protected virtual void DoSelection(int iIndex, bool iSetKeyboardControl, Event iEvent) 
        {
	        ListSelection.Select(PressIndex = iIndex);
	        // 设置Keyboard
	        if (iSetKeyboardControl) 
	        {
		        GUIUtility.keyboardControl = ControlId;
	        }

	        iEvent.Use();
        }
        
        /// <summary>
        /// 列表选中处理 - 前处理
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        protected void HandlePreSelection(Rect iRect, Event iEvent) 
        {
            if (iEvent.type == EventType.MouseDrag && Draggable && GUIUtility.hotControl == ControlId) 
            {
                if (ListSelection.Length > 0 && UpdateDragPosition(iEvent.mousePosition, iRect, DragRectsList)) 
                {
                    GUIUtility.keyboardControl = ControlId;
                    Dragging = true;
                }
                iEvent.Use();
            }
        }
        
        /// <summary>
        /// 列表选中处理 - 后处理
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        protected virtual void HandlePostSelection(Rect iRect, Event iEvent) 
		{
			switch (iEvent.GetTypeForControl(ControlId)) 
			{
				// 鼠标按下
				case EventType.MouseDown:

					if (iRect.Contains(iEvent.mousePosition) && IsMouseLeftOrMidBtnDown(iEvent)) 
					{
						// 取得选中Element的索引
						var index = MouseClickCheck(iEvent.mousePosition);
						if (CanSelect(index)) 
						{
							// 当前Keyboard无焦点，或者当前焦点目标为当前对象，或者鼠标中间按下
							DoSelection(index, GUIUtility.keyboardControl == 0 || GUIUtility.keyboardControl == ControlId || iEvent.button == 2, iEvent);
						}
						else 
						{
							// 清空选中信息
							ListSelection.Clear();
						}

						HandleUtility.Repaint();
					}

					break;

				// 鼠标抬起
				case EventType.MouseUp:

					// 不可拖拽
					if (!Draggable) 
					{
						// select the single object if no selection modifier is being performed
						// 选中当前按下所选中Element的索引
                        ListSelection.SelectWhenNoAction(PressIndex, iEvent);
					}
					// 当前对象被选中
					else if (GUIUtility.hotControl == ControlId) 
					{
						iEvent.Use();
						// 拖拽中
						if (Dragging) 
						{
                            Dragging = false;
							//move elements in list
							ReorderDraggedElements(DragDirection, DragRectsList.StartIndex, () => DragRectsList.SortByPosition());
						}
						else 
						{

							// if we didn't drag, then select the original pressed object
                            ListSelection.SelectWhenNoAction(PressIndex, iEvent);
						}

						GUIUtility.hotControl = 0;
					}

					HandleUtility.Repaint();

					break;

				// 键盘按键按下
				case EventType.KeyDown:

					if (GUIUtility.keyboardControl == ControlId) 
					{
						// 向下箭头按下
						if (iEvent.keyCode == KeyCode.DownArrow && !Dragging) 
						{
                            ListSelection.Select(0);
							iEvent.Use();
						}
						// 向上箭头按下
						else if (iEvent.keyCode == KeyCode.UpArrow && !Dragging) 
						{

                            ListSelection.Select(0);
							iEvent.Use();
						}
						// Esc键按下
						else if (iEvent.keyCode == KeyCode.Escape && GUIUtility.hotControl == ControlId) 
						{

							GUIUtility.hotControl = 0;
							if (Dragging) 
							{
								Dragging = false;
                                ListSelection = PrevListSelection;
							}

							iEvent.Use();
						}
					}

					break;
			}
		}

#endregion

#region Events

        private int _controlId = -1;
        /// <summary>
        /// 选中的控件Id
        /// </summary>
        protected int ControlId
        {
            get => _controlId;
            private set => _controlId = value;
        }
        
        /// <summary>
        /// 生成Control Id
        /// </summary>
        /// <param name="iRect">当前矩形区域</param>
        /// <param name="iHashCode">Selection Hash Code</param>
        /// <returns>Control Id</returns>
        protected int GenerateControlId(Rect iRect, int iHashCode = -1)
        {
            var hashCode = iHashCode;
            if (-1 == hashCode)
            {
                hashCode = GetType().Name.GetHashCode();
            }
            return UtilsGUIEx.GenerateControlId(iRect, hashCode);
        }
        
        protected virtual int DragAndDropHash => $"{GetType().Name}DragAndDrop".GetHashCode();
        
        /// <summary>
        /// 拖拽Control Id
        /// </summary>
        public int DragDropControlID { get; protected set; } = -1;
        
        /// <summary>
        /// 挂接拖拽
        /// </summary>
        /// <param name="iRect">区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iOnDragAnDropped">拖拽回调</param>
        protected void HandleDragAndDrop(Rect iRect, Event iEvent, AssetsDragAndDropDown iOnDragAnDropped) 
        {
	        switch (iEvent.GetTypeForControl(DragDropControlID)) 
	        {
		        // 拖拽更新
		        case EventType.DragUpdated:
		        // 执行拖拽
		        case EventType.DragPerform:
		        {
			        if (iRect.Contains(iEvent.mousePosition))
			        {
				        var acceptDrag = false;
				        // 拖动文件或者文件夹
				        var paths = DragAndDrop.paths;
				        if (null != paths && 0 < paths.Length)
				        {
					        DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
					        acceptDrag = true;

					        iOnDragAnDropped.Invoke(paths);
					        iEvent.Use();
				        }
                        
				        if (acceptDrag) 
				        {
					        GUI.changed = true;
					        DragAndDrop.AcceptDrag();
				        }
			        }
		        }
			        break;
		        case EventType.DragExited:
		        {
			        if (GUI.enabled) 
			        {
				        HandleUtility.Repaint();
			        }
		        }

			        break;
	        }
        }

        /// <summary>
        /// 挂接鼠标点击事件
        /// <para>* 为选中Element后，鼠标右键菜单</para>
        /// </summary>
        /// <param name="iRect">Element索引</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iControlId">Control Id</param>
        /// <param name="iOnMouseLeftClicked">鼠标左键点击回调</param>
        /// <param name="iOnMouseRightClicked">鼠标右键点击回调</param>
        protected void HandleMouseEvents(Rect iRect, Event iEvent, int iControlId,
	        Action<int> iOnMouseLeftClicked = null, Action<int> iOnMouseRightClicked = null)
        {
	        switch (iEvent.GetTypeForControl(iControlId))
	        {
		        // 拖拽更新
		        case EventType.MouseDown:
		        case EventType.MouseUp:
		        {
			        // 鼠标左键/中键事件
			        if (iRect.Contains(iEvent.mousePosition) && IsMouseLeftOrMidBtnDown(iEvent))
			        {
				        if (null == iOnMouseLeftClicked)
				        {
					        OnMouseLeftClicked(iControlId);
				        }
				        else
				        {
					        iOnMouseLeftClicked.Invoke(iControlId);   
				        }
				        iEvent.Use();
			        }
			        
			        // 鼠标右键时间
			        if (iRect.Contains(iEvent.mousePosition) && IsMouseRightClickDown(iEvent))
			        {
				        if (null == iOnMouseRightClicked)
				        {
					        OnMouseLeftClicked(iControlId);
				        }
				        else
				        {
					        iOnMouseRightClicked.Invoke(iControlId);
				        }
				        iEvent.Use();
			        }
		        }
			        break;
		        default:
			        break;
	        } 
        }
        
        /// <summary>
        /// 鼠标左键点击事件
        /// </summary>
        protected virtual void OnMouseLeftClicked(int iControlId) {}
        
        /// <summary>
        /// 鼠标右键点击事件
        /// </summary>
        protected virtual void OnMouseRightClicked(int iControlId) {}

#endregion

#region Draw
        
        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="iLevel">缩进层级</param>
        public void Draw(int iLevel = 0)
        {
            if (!Initialized)
            {
                InitContents();
                InitStyles();
                
                // 拖拽代理
                if (Draggable)
                {
                    DragSurrogate = GenerateDragSurrogate();
                }
                
                Initialized = true;
            }
            
            var curEvent = Event.current;
            var position = EditorGUILayout.GetControlRect(true, CalcTotalHeight(), EditorStyles.largeLabel);
            
            // 设定缩进
            var lastIndent = EditorGUI.indentLevel;
            EditorGUI.indentLevel = iLevel;
            SelfRect = EditorGUI.IndentedRect(position);
            
            // 绘制背景
            var bgRect = Draw(SelfRect, curEvent);
                    
            // 恢复缩进
            EditorGUI.indentLevel = lastIndent;
        }

        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制范围</returns>
        public virtual Rect Draw(Rect iRect, Event iEvent)
        {
            if (!Initialized)
            {
                InitContents();
                InitStyles();
                
                // 拖拽代理
                if (Draggable)
                {
                    DragSurrogate = GenerateDragSurrogate();
                }
                
                Initialized = true;
            }
            
            // 控件Id
            ControlId = GenerateControlId(iRect);
            if (Draggable)
            {
                DragDropControlID = UtilsGUIEx.GenerateDragControlId(iRect, DragAndDropHash);
            }
            
            // 可点击
            if (Clickable)
            {
	            HandleMouseEvents(iRect, iEvent, ControlId);
            }
            
            return DrawSelf(iRect, iEvent, SelfProperty);
        }

        /// <summary>
        /// 绘制自身
        /// </summary>
        /// <param name="iRect">绘制区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iSelf">自身Property</param>
        protected abstract Rect DrawSelf(Rect iRect, Event iEvent, SerializedProperty iSelf);

#region Background

        /// <summary>
        /// 绘制背景 - 一般
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent)
        {
            return UtilsGUIEx.DrawGenericBg(iRect, iEvent, _options);
        }        
        
        /// <summary>
        /// 绘制背景 - 一般
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iOptions">操作选项</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent, int iOptions)
        {
	        return UtilsGUIEx.DrawGenericBg(iRect, iEvent, iOptions);
        }

        /// <summary>
        /// 绘制背景
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iBgColor">背景色</param>
        /// <param name="iStyle">背景Style</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent, Color iBgColor, GUIStyle iStyle)
        {
            return UtilsGUIEx.DrawGenericBg(iRect, iEvent, iBgColor, iStyle, false, false, _options);
        }
        
        /// <summary>
        /// 绘制背景 - 一般
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iStyle">背景Style</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawGenericBg(Rect iRect, Event iEvent, GUIStyle iStyle)
        {
            return DrawGenericBg(iRect, iEvent, BgColor, iStyle);
        }
        
        /// <summary>
        /// 绘制背景 - 可点击
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawClickableBg(Rect iRect, Event iEvent)
        {
            return DrawGenericBg(iRect, iEvent, UtilsGUIEx.ColorClickable, GuiExHelper.HeaderBackground);
        }
        
        /// <summary>
        /// 绘制背景 - 可拖拽
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected Rect DrawDraggableBg(Rect iRect, Event iEvent)
        {
            return DrawGenericBg(iRect, iEvent, UtilsGUIEx.ColorDraggable, GuiExHelper.HeaderBackground);
        }

#endregion

#endregion
    }
}
